/***************************************************************************
 * Open Object Oriented ANSI C                                             *
 ***************************************************************************
 * Code given under the terms of GNU General Public Licence (GPLv3)        *
 * and without any waranties of any kind including but not limitative to   *
 * waranties on merchandability or any particular applications fitness.    *
 * For more information on GNU/GPL go on :                                 *
 * "http://www.gnu.org/copyleft/gpl.html"                                  *
 *                                                                         *
 * You are allowed to use it for any purposes in the terms of GNU/GPLv3    *
 * (or more).                                                              *
 * This text MUST stay in state on copyed sources (or sources using it)    *
 * and must not be altered.                                                *
 * You are allowed to add your name at the end of the Copylefs list.       *
 ***************************************************************************
 * Copylefts List :                                                        *
 ***************************************************************************
 * 2010-03-20 Patrick PIGNOL <pignol_patrick@hotmail.com> (Original)       *
 * (Type your name here if needed)                                         *
 ***************************************************************************/
#include <stdlib.h>
#include <signal.h>
#include "Mem.h"
#include "Class.h"
#include "Stack.h"

static StackVirtualTable* StackVirtualTableInstance = 0;

Stack* StackNew(unsigned long int pArgsCount, va_list* pParameters)
{
    Stack* this = 0;
    this = malloc(sizeof(Stack));
    if(!this)
    {
        raise(SIGABRT);
    }
    this->VirtualTable = StackInitialize(this, pArgsCount, pParameters);
    this->Constructor = StackConstructor;
    this->Destructor = StackDestructor;
    this->Clone = StackClone;
    this->Push = StackPush;
    this->Pop = StackPop;
    this->Count = StackCount;
    this->Constructor(this, pArgsCount, pParameters);
    return this;
}

StackVirtualTable* StackInitialize(Stack* this, unsigned long int pArgsCount, va_list* pParameters)
{
    if(!StackVirtualTableInstance)
    {
        StackVirtualTableInstance = (StackVirtualTable*) malloc(sizeof(ClassVirtualTable));
        if(!StackVirtualTableInstance)
        {
            raise(SIGABRT);
        }
        StackVirtualTableInstance->Interface = 0;

        StackVirtualTableInstance->TypeID = STACK_TYPEID;

        StackVirtualTableInstance->AncestorTable = ClassInitialize((Class*)this, pArgsCount, pParameters);

        StackVirtualTableInstance->ReferenceCount = 0;

        StackVirtualTableInstance->new = StackNew;
        StackVirtualTableInstance->Initialize = StackInitialize;
        StackVirtualTableInstance->Garbage = (void(*)(Stack*))StackVirtualTableInstance->AncestorTable->Garbage;
        StackVirtualTableInstance->TypeOf = (unsigned long int (*)(Stack*))StackVirtualTableInstance->AncestorTable->TypeOf;
        StackVirtualTableInstance->IsSameTypeThanTypeID = (bool (*)(Stack*, unsigned long int))StackVirtualTableInstance->AncestorTable->IsSameTypeThanTypeID;
        StackVirtualTableInstance->IsKindOfTypeID = (bool (*)(Stack* this, unsigned long int))StackVirtualTableInstance->AncestorTable->IsKindOfTypeID;
        StackVirtualTableInstance->IsSameTypeThan = (bool (*)(Stack* this, Class*))StackVirtualTableInstance->AncestorTable->IsSameTypeThan;
        StackVirtualTableInstance->IsKindOf = (bool (*)(Stack* this, Class*))StackVirtualTableInstance->AncestorTable->IsKindOf;
    }
    StackVirtualTableInstance->ReferenceCount++;
    return StackVirtualTableInstance;
}

void StackConstructor(Stack* this, unsigned long int pArgsCount, va_list* pParameters)
{
    this->aStack = 0;
    this->aCount = 0;
}

void StackDestructor(Stack* this)
{
}

Stack* StackClone(Stack* this)
{
    Stack* vClone = 0;
    unsigned long int vIndex = 0;

    vClone = new((void*(*)(unsigned long int, va_list*))this->VirtualTable->new,0);
    vClone->aStack = (Class**) calloc((this->aCount), sizeof(Class*));
    for(vIndex = 0; vIndex < this->aCount; vIndex++)
    {
        vClone->aStack[vIndex] = this->aStack[vIndex];
    }
    vClone->aCount = this->aCount;

    return vClone;
}

void StackPush(Stack* this, Class* pObject)
{
    if(!this->aStack)
    {
        this->aStack = (Class**) malloc((this->aCount+1) * sizeof(Class*));
    }
    else
    {
        this->aStack = (Class**) realloc(this->aStack, (sizeof(Class*)) * (this->aCount + 1));
    }
    this->aStack[(this->aCount)] = pObject;
    this->aCount++;
}

Class* StackPop(Stack* this)
{
    Class* vResult = 0;
    if(this->aStack)
    {
        vResult = this->aStack[(this->aCount-1)];
        this->aCount--;
        if(!this->aCount)
        {
            free(this->aStack);
            this->aStack = 0;
        }
        else
        {
            this->aStack = (Class**) realloc(this->aStack, (sizeof(Class*)) * (this->aCount));
        }
    }
    return vResult;
}

unsigned long int StackCount(Stack* this)
{
    return this->aCount;
}
